package dfsketches.terrain_generator;

import java.util.Arrays;
import java.util.Map;
import java.util.Random;

public class CosineGenerator implements TerrainGenerator {

	private Random rnd;
	
	/**
	 *
	 *@param params Includes keys "partition", "height", "seed"
	 */
	@Override
	public int[][] generate(int size, Map<String, Object> params) {
		Object oseed = params.get("seed");
		long seed = (oseed instanceof Integer) ? (Integer)oseed : System.nanoTime();

		rnd = new Random(seed);
		int[][] map = new int[size][size];

		Object oparts = params.get("partition");
		int parts = (oparts != null && oparts instanceof Integer) ? (Integer)oparts : 16;
		
		Object oheight = params.get("height");
		float height = (oheight != null && oheight instanceof Float) ? (Float)oheight : 200f;
		
		float[][] nodes = genNodes(parts, height);

		int len = size / parts;
		float k = (float)Math.PI / len;
		float kk = k / len;

		int sx = 0;
		for (int ix = 0; ix < parts; ix ++) {
			int sy = 0;
			for (int iy = 0; iy < parts; iy ++) {
				float a = (nodes[ix][iy] + nodes[ix+1][iy+1]) / 2;
				float b = (nodes[ix][iy] - nodes[ix+1][iy]) / 2;
				float c = (nodes[ix][iy] - nodes[ix][iy+1]) / 2;
				float d = (nodes[ix+1][iy] + nodes[ix][iy+1] - nodes[ix][iy] - nodes[ix+1][iy+1]) / 2;
				for (int x = 0; x < len; x++)
					for (int y = 0; y < len; y++) {
						map[x+sx][y+sy] = (int) (a + b * Math.cos(x * k) +
								c * Math.cos(y * k) + d * Math.cos(x * y * kk));
					}
				sy += len;
			}
			sx += len;
		}

		return map;
	}
	
	private float[][] genNodes(int parts, float height) {
		float deviation = height + 1f;
		float floor = -height / 2f;
		
		float[][] nodes = new float[parts + 1][parts + 1]; 
		for (int j = 1; j < parts; j++) {
			float[] jnodes = nodes[j];
			for (int i = 1; i < parts; i++) {
				jnodes[i] = (int) (rnd.nextFloat() * deviation + floor);
			}
			jnodes[0] = jnodes[parts] = floor;
		}
		Arrays.fill(nodes[0], floor);
		Arrays.fill(nodes[parts], floor);
		return nodes;
	}

}